package cn.opencodes.framework.core.interceptor;


import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import com.google.common.util.concurrent.RateLimiter;

import cn.opencodes.framework.core.service.AlphaService;
import cn.opencodes.framework.core.utils.SpringUtils;
import cn.opencodes.framework.core.utils.WebUtils;
import cn.opencodes.framework.core.vo.MaliciousLog;
import cn.opencodes.framework.core.vo.UserRoot;
import cn.opencodes.framework.tools.utils.JsonUtils;
import cn.opencodes.framework.tools.utils.StringUtils;
import cn.opencodes.framework.tools.vo.CoreConst;

/**
 * 恶意拦截拦截器
 * @author HJ
 */
public class MaliciousInterceptor extends HandlerInterceptorAdapter {
	private Logger logger = LoggerFactory.getLogger(getClass());
	
	private Map<String, String> tokenMap = new HashMap<>();
	private RateLimiter limiter;
	
	public MaliciousInterceptor(RateLimiter limiter) {
		this.limiter = limiter;
	}
	
	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		if(handler instanceof HandlerMethod) {
			logger.debug("拦截URL：{}", WebUtils.getPathWithinApplication(request));
			String token = WebUtils.getRequestToken(request);
			String curMethodName = ((HandlerMethod)handler).getMethod().getName();
			//处理是否恶意请求
			if ( doMalicious(request, curMethodName, token) ) {
				WebUtils.write(response, CoreConst.HttpStatus.ERROR.value(), "系统检测您的请求过于频繁，请稍后再试！");
				return false;
			}
		}
		return super.preHandle(request, response, handler);
	}
	
	private boolean doMalicious(HttpServletRequest request, String curMethodName, String token) {
		//RateLimiter limiter = SpringUtils.getBean(RateLimiter.class);
    	boolean yes = false;
		String preMethodName = tokenMap.get(token);
		// 判断当前请求是否是用户上次请求
		if (StringUtils.isNotBlank(preMethodName) && preMethodName.equals(curMethodName)) {
			if (!limiter.tryAcquire(1000, TimeUnit.MILLISECONDS)) {
				yes = true;
				saveMaliciousReqLog(request);
			}
		}
		tokenMap.put(token, curMethodName);
		return yes;
	}
	
	private void saveMaliciousReqLog(HttpServletRequest request){
		try {
			MaliciousLog log = new MaliciousLog();
			log.setUserAgent(WebUtils.analyticUserAgent(request).toString());
			UserRoot user = WebUtils.getUser();
			log.setUserName(user.getUsername());
			log.setMethod(request.getMethod());
			log.setRequestUrl(request.getServletPath());
			log.setClientHost(WebUtils.getIpAddr());
			log.setParameters(JsonUtils.toJson(request.getParameterMap()));
			log.setCtime(new Date());
			log.setTitle("恶意请求拦截");
			//收集日志
			SpringUtils.getBean(AlphaService.class).collect(log, MaliciousLog.class);
		} catch (Exception e) {
			logger.error("日志恶意拦截器异常:",e);
		}
	}
    
}
